use std::fs;
use std::io;
use std::vec;
use std::path;
use std::ffi::OsStr;

pub fn read_file(path: &str) -> Result<String, io::Error> {
    let r = fs::read_to_string(path)?;
    // return r.is_ok() ? r.unwrap() : r.unwrap_err();
    return Ok(r);
}

pub fn add_two(a: i32) -> i32 {
    prints_and_returns_10(3);
    internal_adder(a, 2)
}

fn internal_adder(a: i32, b: i32) -> i32 {
    a + b
}

fn prints_and_returns_10(a: i32) -> i32 {
    println!("I got the value {}", a);
    10
}

pub fn len(in_str: &str) -> usize {
    return in_str.len();
}

pub fn left(in_str: &str, n: usize) -> &str {
    return &in_str[0..n];
}

pub fn replace_crlf_to_lf(in_str: &str) -> String {
    return in_str.replace("\r\n", "\n");
}

pub fn get_extension(p: &'static path::Path) -> &'static str {
    let ex = p.extension();
    let exx = match ex {
        Some(ee) => {
            let m = match ee.to_str() {
                Some(x) => x,
                None => ""
            };
            m
        },
        None => ""
    };
    return exx;
}

pub fn list_files_with_ext(path: &str, ext: &str) -> vec::Vec<String> {
    let paths = fs::read_dir(path).unwrap();
    return paths.map(|path|{
        return path.unwrap().path();
    }).filter(|p|{
        return p.is_file();
    }).filter(|p|{
        return p.extension() == Some(OsStr::new(ext));
    }).map(|p|{
        let name = p.display().to_string();
        println!("Name: {}", name);
        return name;
    }).collect::<Vec<String>>();
}

pub fn list_files(path: &str) -> vec::Vec<String> {
    return list_files_with_ext(path, "md");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn list_files_work() {
        const S:&str = "./";
        let paths = list_files_with_ext(S, "txt");
        let c = paths.len();
        assert_eq!(c, 1);
        for p in paths {
            assert!(p.len() > 0);
            println!("Name: {}", p);
        }
        let paths = list_files(S);
        assert_eq!(paths.len(), 0);
    }

    #[test]
    fn add_two_test() {
        let a = add_two(3);
        assert_eq!(a, 5);
    }

    #[test]
    fn read_file_works() {
        const S:&str = "test.txt";
        let r = read_file(S);
        assert_eq!(r.unwrap(), "a\r\nbc");
    }

    #[test]
    fn len_works() {
        let s = "abcdefghijklmnopqrstuvwxyz";
        assert_eq!(len(&s), 26);
    }

    #[test]
    fn left_works() {
        const S:&str = "abcdefghijklmnopqrstuvwxyz";
        assert_eq!(left(&S, 9), "abcdefghi");
    }

    #[test]
    fn replace_crlf_to_lf_works() {
        let s = "a\r\nbc";
        assert_eq!(replace_crlf_to_lf(&s), "a\nbc");
    }

    #[test]
    fn get_extension_test() {
        let p = path::Path::new("./test.txt");
        assert_eq!(get_extension(p), "txt");
        let w = path::Path::new("testeee/acbc");
        assert_eq!(get_extension(w), "");
        let w = path::Path::new("testeee/.acbc");
        assert_eq!(get_extension(w), "");
        let w = path::Path::new(".acbc");
        assert_eq!(get_extension(w), "");
    }

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }

    #[test]
    fn internal_test_works() {
        assert_eq!(4, internal_adder(2, 2));
    }

    #[test]
    #[ignore]
    fn this_test_will_pass() {
        let value = prints_and_returns_10(4);
        assert_eq!(10, value);
    }

    #[test]
    fn this_test_will_pass_too() {
        let value = prints_and_returns_10(8);
        assert_eq!(10, value);
    }
}